class cshowwindow {
  // ========== contructor ========== //
  cshowwindow(int rawData[], int pattern[]) {
    this.rawData = rawData;
    this.pattern = pattern;

    MIN_RAW = min(rawData);
    MAX_RAW = max(rawData);

    LEN_RAWDATA = rawData.length;
    LEN_PATTERN = pattern.length;
    LEN_HUE = LEN_RAWDATA - LEN_PATTERN;

    layerRaw = createGraphics(WIDTH, HEIGHT);
    layerPattern = createGraphics(WIDTH, HEIGHT);

    visualizePattern();
  }

  // ========== visualize ========== //
  void visualizePattern() {
    // =========== //
    layerRaw.beginDraw();
    layerRaw.colorMode(HSB, 360, 100, 100);
    layerRaw.strokeWeight(2);
    layerRaw.textSize(30);
    layerRaw.endDraw();

    // =========== //
    int minVal = min(pattern);
    int maxVal = max(pattern);
    int preXpos = 0;
    int preYpos = HEIGHT / 2;

    layerPattern.beginDraw();
    layerPattern.colorMode(HSB, 360, 100, 100);
    layerPattern.background(#F56AB7, 80);

    for (int i = 0; i < LEN_PATTERN; i++) {
      int xpos = (int)map(i, 0, LEN_PATTERN, 0, WIDTH);
      int ypos = (int)map(pattern[i], minVal, maxVal, HEIGHT - 1, 0);
      layerPattern.line(preXpos, preYpos, xpos, ypos);
      preXpos = xpos;
      preYpos = ypos;
    }
    layerPattern.endDraw();
  }

  // ========== update raw data zoom window ========== //
  void update(int mx) {
    if (processedX != mx) {
      processedX = mx;

      int xoffset = (int)map(mouseX, 0, width, 0, LEN_RAWDATA);

      int tmp = constrain(xoffset, 0, LEN_HUE - 1);
      int hue = diff2.getHue(tmp);
      int mr = diff2.getMatchingRate(tmp);

      int preXpos = 0;
      int preYpos = HEIGHT / 2;

      layerRaw.beginDraw();
      layerRaw.background(#FFFFFF);
      layerRaw.stroke(hue, 100, 100);
      layerRaw.fill(hue + 150, 100, 100);

      for (int i = 0; i < LEN_PATTERN; i++) {
        int raw_i = xoffset + i;
        if (raw_i >= LEN_RAWDATA) break;
        int xpos = (int)map(i, 0, LEN_PATTERN, 0, WIDTH);
        int ypos = (int)map(rawData[raw_i], MIN_RAW, MAX_RAW, HEIGHT - 1, 0);
        layerRaw.line(preXpos, preYpos, xpos, ypos);
        preXpos = xpos;
        preYpos = ypos;
      }

      layerRaw.text(xoffset, 0, 20);
      layerRaw.text(mr + "%", 0, 180);

      layerRaw.endDraw();
    }
  }

  // ========== show ========== //
  void show() {
    int mx = mouseX;

    if (mx + WIDTH > width) {
      mx -= WIDTH;
    }
    image(layerRaw, mx, 110);
    image(layerPattern, mx, 710);
  }

  // ========== member var ========== //
  private final int rawData[];
  private final int pattern[];
  private int processedX = -1;

  private final int MIN_RAW;
  private final int MAX_RAW;

  private final int LEN_RAWDATA;
  private final int LEN_PATTERN;
  private final int LEN_HUE;

  private final int WIDTH = 450;
  private final int HEIGHT = 180;

  private PGraphics layerRaw;
  private PGraphics layerPattern;
};
